// ============================================
// internal/service/batch_service.go
// ============================================

package service

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/google/uuid"
	"github.com/sirupsen/logrus"

	"virt-manager-go/internal/domain"
)

type batchService struct {
	vmService       domain.VMService
	snapshotService domain.SnapshotService
	logger          *logrus.Logger

	// 批量操作状态跟踪
	batches   map[string]*domain.BatchStatus
	batchesMu sync.RWMutex
}

func NewBatchService(
	vmService domain.VMService,
	snapshotService domain.SnapshotService,
	logger *logrus.Logger,
) domain.BatchService {
	return &batchService{
		vmService:       vmService,
		snapshotService: snapshotService,
		logger:          logger,
		batches:         make(map[string]*domain.BatchStatus),
	}
}

// BatchStartVMs 批量启动虚拟机
func (s *batchService) BatchStartVMs(ctx context.Context, connID string, vmNames []string) (*domain.BatchResult, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"count":      len(vmNames),
	}).Info("Starting batch VM start operation")

	return s.executeBatchOperation(ctx, "start", vmNames, func(ctx context.Context, vmName string) error {
		return s.vmService.StartVM(ctx, connID, vmName)
	})
}

// BatchStopVMs 批量停止虚拟机
func (s *batchService) BatchStopVMs(ctx context.Context, connID string, vmNames []string, force bool) (*domain.BatchResult, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"count":      len(vmNames),
		"force":      force,
	}).Info("Starting batch VM stop operation")

	return s.executeBatchOperation(ctx, "stop", vmNames, func(ctx context.Context, vmName string) error {
		return s.vmService.ShutdownVM(ctx, connID, vmName, force)
	})
}

// BatchRebootVMs 批量重启虚拟机
func (s *batchService) BatchRebootVMs(ctx context.Context, connID string, vmNames []string) (*domain.BatchResult, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"count":      len(vmNames),
	}).Info("Starting batch VM reboot operation")

	return s.executeBatchOperation(ctx, "reboot", vmNames, func(ctx context.Context, vmName string) error {
		return s.vmService.RebootVM(ctx, connID, vmName)
	})
}

// BatchDeleteVMs 批量删除虚拟机
func (s *batchService) BatchDeleteVMs(ctx context.Context, connID string, vmNames []string, removeStorage bool) (*domain.BatchResult, error) {
	s.logger.WithFields(logrus.Fields{
		"connection":     connID,
		"count":          len(vmNames),
		"remove_storage": removeStorage,
	}).Info("Starting batch VM delete operation")

	return s.executeBatchOperation(ctx, "delete", vmNames, func(ctx context.Context, vmName string) error {
		return s.vmService.DeleteVM(ctx, connID, vmName, removeStorage)
	})
}

// BatchCreateSnapshots 批量创建快照
func (s *batchService) BatchCreateSnapshots(ctx context.Context, connID string, vmNames []string, config *domain.SnapshotConfig) (*domain.BatchResult, error) {
	s.logger.WithFields(logrus.Fields{
		"connection":    connID,
		"count":         len(vmNames),
		"snapshot_name": config.Name,
	}).Info("Starting batch snapshot creation")

	return s.executeBatchOperation(ctx, "create_snapshot", vmNames, func(ctx context.Context, vmName string) error {
		// 为每个虚拟机创建唯一的快照名称
		snapConfig := *config
		snapConfig.Name = fmt.Sprintf("%s-%s", config.Name, vmName)

		_, err := s.snapshotService.CreateSnapshot(ctx, connID, vmName, &snapConfig)
		return err
	})
}

// BatchDeleteSnapshots 批量删除快照
func (s *batchService) BatchDeleteSnapshots(ctx context.Context, connID string, operations []domain.SnapshotOperation) (*domain.BatchResult, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"count":      len(operations),
	}).Info("Starting batch snapshot deletion")

	batchID := uuid.New().String()
	result := &domain.BatchResult{
		BatchID:   batchID,
		Total:     len(operations),
		Results:   make([]domain.OperationResult, 0, len(operations)),
		StartTime: time.Now(),
	}

	// 并发执行
	var wg sync.WaitGroup
	resultsCh := make(chan domain.OperationResult, len(operations))

	for _, op := range operations {
		wg.Add(1)
		go func(op domain.SnapshotOperation) {
			defer wg.Done()

			target := fmt.Sprintf("%s/%s", op.VMName, op.SnapshotName)
			err := s.snapshotService.DeleteSnapshot(ctx, connID, op.VMName, op.SnapshotName, false)

			opResult := domain.OperationResult{
				Target:  target,
				Success: err == nil,
			}
			if err != nil {
				opResult.Error = err.Error()
			}

			resultsCh <- opResult
		}(op)
	}

	// 等待所有操作完成
	go func() {
		wg.Wait()
		close(resultsCh)
	}()

	// 收集结果
	for opResult := range resultsCh {
		result.Results = append(result.Results, opResult)
		if opResult.Success {
			result.Successful++
		} else {
			result.Failed++
		}
	}

	result.EndTime = time.Now()
	result.Duration = result.EndTime.Sub(result.StartTime)

	return result, nil
}

// BatchUpdateVMs 批量更新虚拟机配置
func (s *batchService) BatchUpdateVMs(ctx context.Context, connID string, updates []domain.VMUpdate) (*domain.BatchResult, error) {
	s.logger.WithFields(logrus.Fields{
		"connection": connID,
		"count":      len(updates),
	}).Info("Starting batch VM update operation")

	batchID := uuid.New().String()
	result := &domain.BatchResult{
		BatchID:   batchID,
		Total:     len(updates),
		Results:   make([]domain.OperationResult, 0, len(updates)),
		StartTime: time.Now(),
	}

	// 并发执行
	var wg sync.WaitGroup
	resultsCh := make(chan domain.OperationResult, len(updates))

	for _, update := range updates {
		wg.Add(1)
		go func(update domain.VMUpdate) {
			defer wg.Done()

			err := s.vmService.UpdateVMConfig(ctx, connID, update.VMName, update.Config)

			opResult := domain.OperationResult{
				Target:  update.VMName,
				Success: err == nil,
			}
			if err != nil {
				opResult.Error = err.Error()
			}

			resultsCh <- opResult
		}(update)
	}

	// 等待所有操作完成
	go func() {
		wg.Wait()
		close(resultsCh)
	}()

	// 收集结果
	for opResult := range resultsCh {
		result.Results = append(result.Results, opResult)
		if opResult.Success {
			result.Successful++
		} else {
			result.Failed++
		}
	}

	result.EndTime = time.Now()
	result.Duration = result.EndTime.Sub(result.StartTime)

	return result, nil
}

// GetBatchStatus 获取批量操作状态
func (s *batchService) GetBatchStatus(ctx context.Context, batchID string) (*domain.BatchStatus, error) {
	s.batchesMu.RLock()
	defer s.batchesMu.RUnlock()

	status, exists := s.batches[batchID]
	if !exists {
		return nil, fmt.Errorf("batch operation not found")
	}

	return status, nil
}

// === 辅助方法 ===

// executeBatchOperation 执行批量操作的通用方法
func (s *batchService) executeBatchOperation(
	ctx context.Context,
	operation string,
	targets []string,
	operationFunc func(context.Context, string) error,
) (*domain.BatchResult, error) {
	batchID := uuid.New().String()

	// 创建批量操作状态
	status := &domain.BatchStatus{
		BatchID:  batchID,
		Status:   "running",
		Progress: 0,
	}

	s.batchesMu.Lock()
	s.batches[batchID] = status
	s.batchesMu.Unlock()

	result := &domain.BatchResult{
		BatchID:   batchID,
		Total:     len(targets),
		Results:   make([]domain.OperationResult, 0, len(targets)),
		StartTime: time.Now(),
	}

	// 使用信号量限制并发数
	semaphore := make(chan struct{}, 10) // 最多 10 个并发操作
	var wg sync.WaitGroup
	resultsCh := make(chan domain.OperationResult, len(targets))

	// 启动进度更新
	go s.updateBatchProgress(ctx, batchID, len(targets), resultsCh)

	for _, target := range targets {
		wg.Add(1)
		go func(target string) {
			defer wg.Done()

			// 获取信号量
			semaphore <- struct{}{}
			defer func() { <-semaphore }()

			err := operationFunc(ctx, target)

			opResult := domain.OperationResult{
				Target:  target,
				Success: err == nil,
			}
			if err != nil {
				opResult.Error = err.Error()
				s.logger.WithError(err).WithFields(logrus.Fields{
					"operation": operation,
					"target":    target,
				}).Warn("Batch operation failed for target")
			}

			resultsCh <- opResult
		}(target)
	}

	// 等待所有操作完成
	go func() {
		wg.Wait()
		close(resultsCh)
	}()

	// 收集结果
	for opResult := range resultsCh {
		result.Results = append(result.Results, opResult)
		if opResult.Success {
			result.Successful++
		} else {
			result.Failed++
		}
	}

	result.EndTime = time.Now()
	result.Duration = result.EndTime.Sub(result.StartTime)

	// 更新最终状态
	s.batchesMu.Lock()
	status.Status = "completed"
	status.Progress = 100
	status.Results = result
	s.batchesMu.Unlock()

	s.logger.WithFields(logrus.Fields{
		"batch_id":   batchID,
		"operation":  operation,
		"total":      result.Total,
		"successful": result.Successful,
		"failed":     result.Failed,
		"duration":   result.Duration,
	}).Info("Batch operation completed")

	return result, nil
}

// updateBatchProgress 更新批量操作进度
func (s *batchService) updateBatchProgress(ctx context.Context, batchID string, total int, resultsCh <-chan domain.OperationResult) {
	completed := 0

	for range resultsCh {
		completed++
		progress := float64(completed) / float64(total) * 100

		s.batchesMu.Lock()
		if status, exists := s.batches[batchID]; exists {
			status.Progress = progress
		}
		s.batchesMu.Unlock()
	}
}
